﻿using System;
using System.Diagnostics;

namespace dPet.Application.Services.Implementation
{
	using dPet.Infrastructure.Logging;
	using Hangerd;
	using Hangerd.Components;
	using Hangerd.Entity;
	using Hangerd.Extensions;
	using Hangerd.Repository;

	public class ServiceBase
	{
		#region Unit of work

		private readonly IRepositoryContext _unitOfWork;

		protected IRepositoryContext UnitOfWork
		{
			get { return _unitOfWork; }
		}

		#endregion

		public ServiceBase(IRepositoryContext unitOfWork)
		{
			_unitOfWork = unitOfWork;
		}

		protected delegate TResult LoggedOperatingDelegate<TResult, TEntity>(ref TEntity root)
			where TEntity : EntityBase;

		private static IOperatingLoggingService OperatingLoggingService
		{
			get { return LocalServiceLocator.GetService<IOperatingLoggingService>(); }
		}

		protected static MessagedResult<TResult> TryLoggedOperate<TResult, TEntity>(IOperator @operator, string moduleName, string operatingName,
			LoggedOperatingDelegate<TResult, TEntity> operate, string successMessage = "操作成功", string failureMessage = "操作失败")
			where TEntity : EntityBase
		{
			TEntity aggregateRoot = null;
			var success = true;
			var stopWatch = Stopwatch.StartNew();

			try
			{
				return new MessagedResult<TResult>(operate(ref aggregateRoot), successMessage);
			}
			catch (HangerdException ex)
			{
				success = false;

				return new MessagedResult<TResult>(default(TResult), string.Format("{0}（{1}）", failureMessage, ex.Message));
			}
			catch (Exception ex)
			{
				success = false;

				LocalLoggingService.Exception("TryLoggedOperate Error! Module:{0}, Operating:{1}", moduleName, operatingName);
				LocalLoggingService.Exception(ex);

				return new MessagedResult<TResult>(default(TResult), failureMessage);
			}
			finally
			{
				stopWatch.Stop();

				if (success)
				{
					//记录操作日志，聚合根属性变更监控
					OperatingLoggingService.AddLog(@operator, moduleName, operatingName,
						aggregateRoot != null ? aggregateRoot.Id : string.Empty,
						aggregateRoot != null ? aggregateRoot.ModifiedPropertiesRecords.ObjectToJson() : string.Empty,
						stopWatch.ElapsedMilliseconds);
				}
			}
		}
	}
}
